#include "pages.hpp"
#include "core.hpp"
#include <map>
extern std::map<uint64_t, Semaphore<std::array<char, 4096>>> memory;

uint64_t to_uint64(PTE pte)
{
	uint64_t result = std::get<2>(pte);
	result = (result << 8) | std::get<1>(pte);
	result = (result << 40) | std::get<0>(pte);
	return result;
}

TLB::TLB(MessageBus *bus)
{
	this->bus = bus;
	this->table = new std::tuple<uint64_t, uint64_t, PTE>[256];
}
void TLB::translate()
{
	uint64_t pageID = bus->MAR >> 12;
	uint8_t index = pageID & 0xff;
	uint64_t tag = pageID >> 8;
	if (std::get<0>(table[index]) == tag) // 查找到页表项
	{
		PTE pte = std::get<2>(table[index]);
		if (std::get<2>(pte) & Valid) // 有效位
		{
			if (std::get<1>(pte) & P) // 特权级要求
				if (!bus->priv)
				{
				access_error:
					bus->sregs[Status][bus->priv] |= (Error | IntTR);
					bus->sregs[Cause][bus->priv] = 0x82;
					bus->sregs[IT][bus->priv] |= 1 << 8;
				}
			if ((std::get<1>(pte) & 0x07) & bus->access) // 权限验证通过
			{
				if (std::get<2>(pte) ^ Cache_EN) // 检验Cache是否启用
					bus->sregs[Status][bus->priv] ^= CacheEN;
				if (bus->access & W) // 写入标记
					std::get<2>(std::get<2>(table[index])) |= Dirty;
				bus->MAR &= 0xfff;
				bus->MAR |= std::get<0>(pte) << 12;
				return;
			}
			else
				goto access_error;
		}
		else
			update();
	}
	else
		update();
}
void TLB::update()
{
	uint64_t pageID = bus->MAR >> 12;
	uint64_t pTemp = 0;
	uint64_t addr = 0;
	uint8_t index = pageID & 0xff;
	uint16_t memIndex = 0;
	PTE temp = std::get<2>(table[index]);
	if (std::get<2>(temp) & Dirty)
		store(index);
	// 检查三级页表寄存器是否匹配
	if (PRegs[2].first == (pageID >> 9))
	{
	PageLev3:
		memIndex = (pageID >> 18) & 0x1ff;
		addr = bus->sregs[PDTR][bus->priv] << 12;
		addr += memIndex << 3;
		// 取三级页表项
		memory[addr >> 12].rlock();
		memcpy(&pTemp, memory[addr >> 12].get().data(), 8);
		memory[addr >> 12].r_unlock();
		temp = {pTemp & 0xfffffffff, (pTemp >> 40) & 0x0f, (pTemp >> 48) & 0xff}; // 转换到页表项
		if (std::get<2>(temp) & Valid)
		// 页表项有效
		{
			if (std::get<1>(temp) & P) // 特权级要求
				if (!bus->priv)
				{
				access_error:
					bus->sregs[Status][bus->priv] |= (Error | IntTR);
					bus->sregs[Cause][bus->priv] = 0x82;
					bus->sregs[IT][bus->priv] |= 1 << 8;
				}
			if ((std::get<1>(temp) & 0x07) & bus->access) // 权限验证通过
			{
				if (std::get<2>(temp) ^ Cache_EN) // 检验Cache是否启用
					bus->sregs[Status][bus->priv] ^= CacheEN;
				if (bus->access & W) // 写入标记
					std::get<2>(std::get<2>(table[index])) |= Dirty;
				bus->MAR &= 0xfff;
				bus->MAR |= std::get<0>(temp) << 12;
				table[index] = {pageID >> 8, addr, temp};
				return;
			}
			else
				goto access_error;
		}
		else
		{
		error_page_fault:
			bus->sregs[Status][bus->priv] |= (Error | IntTR);
			bus->sregs[Cause][bus->priv] = 0x81;
			bus->sregs[IT][bus->priv] |= 1 << 8;
		}
		return;
	}
	// 检查二级页表寄存器是否匹配
	else if (PRegs[1].first == (pageID >> 18))
	{
	PageLev2:
		memIndex = (pageID >> 9) & 0x1ff;
		addr = bus->sregs[PDTR][bus->priv] << 12;
		addr += memIndex << 3;
		// 取三级页表起始地址
		memory[addr >> 12].rlock();
		memcpy(&pTemp, memory[addr >> 12].get().data(), 8);
		memory[addr >> 12].r_unlock();
		addr = pTemp;
		if ((addr >> 48) ^ IsChild) // 二级页表项不是子页表
			goto error_page_fault;
		else
			PRegs[2] = {pageID >> 9, addr & 0xfffffffff};
		goto PageLev3;
	}
	// 检查一级页表寄存器是否匹配
	else if (PRegs[0].first == (pageID >> 27))
	{
	PageLev1:
		memIndex = (pageID >> 18) & 0x1ff;
		addr = bus->sregs[PDTR][bus->priv] << 12;
		addr += memIndex << 3;
		// 取二级页表起始地址
		memory[addr >> 12].rlock();
		memcpy(&pTemp, memory[addr >> 12].get().data(), 8);
		memory[addr >> 12].r_unlock();
		addr = pTemp;
		if ((addr >> 48) ^ IsChild) // 二级页表项不是子页表
			goto error_page_fault;
		else
			PRegs[1] = {pageID >> 18, addr & 0xfffffffff};
		goto PageLev2;
	}
	// 从根页表开始操作
	else
	{
		memIndex = (pageID >> 27) & 0x1ff;
		addr = bus->sregs[PDTR][bus->priv] << 12;
		addr += memIndex << 3;
		// 取一级页表起始地址
		memory[addr >> 12].rlock();
		memcpy(&pTemp, memory[addr >> 12].get().data(), 8);
		memory[addr >> 12].r_unlock();
		addr = pTemp;
		if ((addr >> 48) ^ IsChild) // 一级页表项不是子页表
			goto error_page_fault;
		else
			PRegs[0] = {pageID >> 27, addr & 0xfffffffff};
		goto PageLev1;
	}
}
void TLB::store(int index)
{
	uint64_t mem = to_uint64(std::get<2>(table[index]));
	uint64_t addr = std::get<1>(table[index]);
	memory[addr >> 12].w_lock();
	memcpy(memory[addr >> 12].get().data(), &mem, 8);
	memory[addr >> 12].w_unlock();
}
void TLB::flush()
{
	for (int i = 0; i < 256; i++)
	{
		if (std::get<2>(std::get<2>(table[i])) & Dirty)
			store(i);
		std::get<2>(table[i]) = {0, 0, 0};
	}
}
void TLB::run()
{
	while (bus->sregs[Status][bus->priv] ^ Halt)
	{
		bus->cMAR.lock();	 // 等待CalcCore完成MAR写入
		if (bus->size == 0xffff) // 关机
		{
			bus->tMAR.unlock();
			return;
		}
		if (bus->sregs[Status][bus->priv] ^ PageEN) // 未启用分页内存
			goto end;
		else if (bus->access & IO)
			goto end;
		translate();
		if (bus->sregs[Status][bus->priv] ^ TLB_EN) // 如果TLB未启用，则清空TLB
			flush();
	end:
		bus->tMAR.unlock(); // 释放MAR，供MemCore使用
	}
}